package com.cqw.threaddemo.synchronize;


/**
 * $ javap -c -verbose SyncCodeBlock.class
 * 反编译得到如下字节码：
 *
 *
 * Classfile /F:/learning/ThreadDemo/target/classes/com/cqw/threaddemo/synchronize/SyncCodeBlock.class
 *   Last modified 2021-1-15; size 546 bytes
 *   MD5 checksum 11bb62f2db590dc32fa76a619ed74f82
 *   Compiled from "SyncCodeBlock.java"
 * public class com.cqw.threaddemo.synchronize.SyncCodeBlock
 *   minor version: 0
 *   major version: 52
 *   flags: ACC_PUBLIC, ACC_SUPER
 * Constant pool:
 * //常量池中数据
 *    #1 = Methodref          #4.#21         // java/lang/Object."<init>":()V
 *    #2 = Fieldref           #3.#22         // com/cqw/threaddemo/synchronize/SyncCodeBlock.i:I
 *    #3 = Class              #23            // com/cqw/threaddemo/synchronize/SyncCodeBlock
 *    #4 = Class              #24            // java/lang/Object
 *    #5 = Utf8               i
 *    #6 = Utf8               I
 *    #7 = Utf8               <init>
 *    #8 = Utf8               ()V
 *    #9 = Utf8               Code
 *   #10 = Utf8               LineNumberTable
 *   #11 = Utf8               LocalVariableTable
 *   #12 = Utf8               this
 *   #13 = Utf8               Lcom/cqw/threaddemo/synchronize/SyncCodeBlock;
 *   #14 = Utf8               syncTask
 *   #15 = Utf8               StackMapTable
 *   #16 = Class              #23            // com/cqw/threaddemo/synchronize/SyncCodeBlock
 *   #17 = Class              #24            // java/lang/Object
 *   #18 = Class              #25            // java/lang/Throwable
 *   #19 = Utf8               SourceFile
 *   #20 = Utf8               SyncCodeBlock.java
 *   #21 = NameAndType        #7:#8          // "<init>":()V
 *   #22 = NameAndType        #5:#6          // i:I
 *   #23 = Utf8               com/cqw/threaddemo/synchronize/SyncCodeBlock
 *   #24 = Utf8               java/lang/Object
 *   #25 = Utf8               java/lang/Throwable
 * {
 *   public int i;
 *     descriptor: I
 *     flags: ACC_PUBLIC
 *
 * //构造函数
 *   public com.cqw.threaddemo.synchronize.SyncCodeBlock();
 *     descriptor: ()V
 *     flags: ACC_PUBLIC
 *     Code:
 *       stack=1, locals=1, args_size=1
 *          0: aload_0
 *          1: invokespecial #1                  // Method java/lang/Object."<init>":()V
 *          4: return
 *       LineNumberTable:
 *         line 3: 0
 *       LocalVariableTable:
 *         Start  Length  Slot  Name   Signature
 *             0       5     0  this   Lcom/cqw/threaddemo/synchronize/SyncCodeBlock;
 *
 *   public void syncTask();
 *     descriptor: ()V
 *     flags: ACC_PUBLIC
 *     Code:
 *       stack=3, locals=3, args_size=1
 *          0: aload_0
 *          1: dup
 *          2: astore_1
 *          3: monitorenter                 //进入同步方法
 *          4: aload_0
 *          5: dup
 *          6: getfield      #2                  // Field i:I
 *          9: iconst_1
 *         10: iadd
 *         11: putfield      #2                  // Field i:I
 *         14: aload_1
 *         15: monitorexit                  //退出同步方法
 *         16: goto          24
 *         19: astore_2
 *         20: aload_1
 *         21: monitorexit                  //退出同步方法
 *         22: aload_2
 *         23: athrow
 *         24: return
 *       Exception table:
 *          from    to  target type
 *              4    16    19   any
 *             19    22    19   any
 *       LineNumberTable:
 *         line 9: 0
 *         line 10: 4
 *         line 11: 14
 *         line 12: 24
 *       LocalVariableTable:
 *         Start  Length  Slot  Name   Signature
 *             0      25     0  this   Lcom/cqw/threaddemo/synchronize/SyncCodeBlock;
 *       StackMapTable: number_of_entries = 2
 *         frame_type = 255 // full_frame
 *           offset_delta = 19
 *           locals = [ class com/cqw/threaddemo/synchronize/SyncCodeBlock, class java/lang/Object ]
 *           stack = [ class java/lang/Throwable ]
 *         frame_type = 250 // chop
 *           offset_delta = 4
 * }
 * SourceFile: "SyncCodeBlock.java"
 */
public class SyncCodeBlock {

    public int i;

    /**
     * 从字节码中可知同步语句块的实现使用的是monitorenter 和 monitorexit 指令，其中monitorenter指令指向同步代码块的开始位置，monitorexit指令则指明同步代码块的结束位置，
     * 当执行monitorenter指令时，当前线程将试图获取 objectref(即对象锁) 所对应的 monitor 的持有权，当 objectref 的 monitor 的进入计数器为 0，那线程可以成功取得 monitor，
     * 并将计数器值设置为 1，取锁成功。如果当前线程已经拥有 objectref 的 monitor 的持有权，那它可以重入这个 monitor (关于重入性稍后会分析)，重入时计数器的值也会加 1。
     * 倘若其他线程已经拥有 objectref 的 monitor 的所有权，那当前线程将被阻塞，直到正在执行线程执行完毕，即monitorexit指令被执行，执行线程将释放 monitor(锁)并设置计数器值为0 ，其他线程将有机会持有 monitor 。
     * 值得注意的是编译器将会确保无论方法通过何种方式完成，方法中调用过的每条 monitorenter 指令都有执行其对应 monitorexit 指令，而无论这个方法是正常结束还是异常结束。
     * 为了保证在方法异常完成时 monitorenter 和 monitorexit 指令依然可以正确配对执行，编译器会自动产生一个异常处理器，这个异常处理器声明可处理所有的异常，它的目的就是用来执行 monitorexit 指令。
     * 从字节码中也可以看出多了一个monitorexit指令，它就是异常结束时被执行的释放monitor 的指令
     */
    public void syncTask(){
        //同步代码库
        synchronized (this){
            i++;
        }
    }
}